// field_relate.cpp
// Customizer_Base
// Protea Customizer/Customizer Pro / Business Logic for managing field relations
// Copyright (C) 2003, 2004, 2005 eXegeSys, Inc.
// Copyright (C) 2008 Bruce A. James
//
// This program is part of the Protea Project.
//
// The Protea Project is free software; you can redistribute it and/or modify it 
// under the terms of the GNU General Public License as published by the 
// Free Software Foundation, either version 3 of the License, or (at your 
// option) any later version.
//
// The Protea Project is distributed in the hope that it will be useful, but 
// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 
// for more details.
// 
// You should have received a copy of the GNU General Public License along 
// with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// Please send correspondence to:
//
// theproteaproject@gmail.com
//

#include "base_setup.h"

//@ SEC 3
//@ CHA Field Relate Verify
//@ COD FieldRelateVerify
//@ TAB FieldRelate Read
//@ GEN Use FieldRelateVerify to verify field descriptor record

void FieldRelateVerify( XCBuffer* input, verify_type verify_mode, XCTransactionVars* vars ) {
	TRANS_INFUNC( FieldRelateVerify );

	//@ SUB ValidateName to check for a valid name
	ValidateName( FLD_MSTR_FIELD_NAME, vars->buffer, ERR_FIELD, vars );

	//@ Verify that the master field exists
	if (!LookupNumberFromName( vars, vars->buffer, input, FLD_MSTR_FIELD_NBR, FLD_MSTR_FIELD_NAME, FMT_FIELD_DESCRIPTOR, FLD_FIELD_NUMBER, FLD_FIELD_NAME ))
		vars->Errors->Add( ERR_DOESNT_EXIST, SEV_CRITICAL, FLD_MSTR_FIELD_NBR, 1, ERR_FIELD );

	if (verify_mode != VERIFY_REVIEW) {
		//@ SUB ValidateName to check for a valid name
		ValidateName( FLD_FIELD_NAME, vars->buffer, ERR_FIELD, vars );

		//@ Verify that the target field exists
		if (!LookupNumberFromName( vars, vars->buffer, input, FLD_FIELD_NUMBER, FLD_FIELD_NAME, FMT_FIELD_DESCRIPTOR ))
			vars->Errors->Add( ERR_DOESNT_EXIST, SEV_CRITICAL, FLD_FIELD_NAME, 1, ERR_FIELD );

		//@ Determine if a relation record already exists for these fields
		bool exists = FieldRelateRetrieve( input, vars );

		//@ If verifying an ADD transaction,
		if (verify_mode == VERIFY_ADD) {
			//@ GRS
			//@ If this record already exists,
			//@ ERR C (ALREADY_EXISTS) Field already exists
			if ( exists )
				vars->Errors->Add( ERR_ALREADY_EXISTS, SEV_CRITICAL, FLD_FIELD_NAME, 1, ERR_FIELD );

			//@ GRE
		} else { // Review, Change or delete
			//@ GRS
			//@ If this record doesn't exist,
			//@ ERR E (DOESNT_EXIST) Field doesn't exist
			if (!exists)
				vars->Errors->Add( ERR_DOESNT_EXIST, SEV_CRITICAL, FLD_FIELD_NAME, 1, ERR_FIELD );

			//@ GRE
		};
	};

	TRANS_OUTFUNC();
};


//@ SEC 3
//@ CHA Field Relate Retrieve
//@ COD FieldDescRetrieve
//@ TAB FieldDescriptor Read
//@ GEN Use FieldDescRetrieve to retrieve field descriptor record
bool FieldRelateRetrieve( XCBuffer* field_relate, XCTransactionVars* vars ) {
	TRANS_INFUNC( FieldRelateRetrieve );

	XCDBStatement* stmt = NULL;
	XCSQLGen* query = vars->query;
	bool result;

	//@ Attempt to read FIELD_RELATE record
	try {
		query->MakeFull( SQL_STMT_SELECT, field_relate );
		stmt = vars->dbtxn->ExecuteSQL( query );
		result = !stmt->Eof();
		App->CleanupObjects( 1, &stmt );
	} catch( ... ) {
		App->CleanupObjects( 1, &stmt );
		throw;
	};

	TRANS_OUTFUNCRET( result );
};


//@ SEC 3
//@ CHA Field Relate Add
//@ COD FieldDescAdd
//@ TAB FieldDescriptor Read
//@ GEN Use FieldDescRetrieve to retrieve field descriptor record
void FieldRelateAdd( XCBuffer* field_relate, XCTransactionVars* vars ) {
	TRANS_INFUNC( FieldRelateAdd );
	XCField* clone = NULL;
	XCSQLGen* query = vars->query;

	XCField* master;
	XCField* target;

	//@ Attempt to read FIELD_RELATE record
	try {
		query->MakeFull( SQL_STMT_INSERT, field_relate );
		vars->dbtxn->ExecuteSQL( query, SQL_NO_RESULT );

		target = field_relate->GetField( FLD_FIELD_NUMBER );
		master = field_relate->GetField( FLD_MSTR_FIELD_NBR );
		clone = target->Clone();
		target->MoveField( master );
		master->MoveField( clone );
		query->MakeFull( SQL_STMT_INSERT, field_relate );
		vars->dbtxn->ExecuteSQL( query, SQL_NO_RESULT );

		App->CleanupObjects( 1, &clone );
	} catch( ... ) {
		App->CleanupObjects( 1, &clone );
		throw;
	};

	TRANS_OUTFUNC();
};


//@ SEC 3
//@ CHA Field Relate Delete
//@ COD FieldDescAdd
//@ TAB FieldDescriptor Read
//@ GEN Use FieldDescRetrieve to retrieve field descriptor record
void FieldRelateDelete( XCBuffer* field_relate, XCTransactionVars* vars ) {
	TRANS_INFUNC( FieldRelateDelete );

	XCField* clone = NULL;
	XCSQLGen* query = vars->query;

	//@ Attempt to read FIELD_RELATE record
	try {
		query->MakeFull( SQL_STMT_DELETE, field_relate );
		vars->dbtxn->ExecuteSQL( query, SQL_NO_RESULT );

		clone = field_relate->GetField( FLD_FIELD_NUMBER )->Clone();
		field_relate->MoveUnlikeField( FLD_FIELD_NUMBER, field_relate, FLD_MSTR_FIELD_NBR );
		field_relate->GetField( FLD_MSTR_FIELD_NBR )->MoveField( clone );

		query->MakeFull( SQL_STMT_DELETE, field_relate );
		vars->dbtxn->ExecuteSQL( query, SQL_NO_RESULT );
		App->CleanupObjects( 1, &clone );
	} catch( ... ) {
		App->CleanupObjects( 1, &clone );
		throw;
	};

	TRANS_OUTFUNC();
};

//@ SEC 3
//@ CHA Field Relate Find
//@ COD FieldRelateFind
//@ TAB FieldDescriptor Write
//@ GEN Use FieldRelateFind to locate field relation records for a particular field

XCDBStatement* FieldRelateFind( XCBuffer* input, XCTransactionVars* vars ) {
	XCSQLGen* query = vars->query;
	XCCompare comp[2];
	XCField* fields[3];

	fields[0] = input->GetField( FLD_APPL_NBR );
	fields[1] = input->GetField( FLD_MSTR_FIELD_NBR );
	fields[2] = NULL;

	query->MakeSELECT( input );
	query->AddWHERE( fields, comp );

	return vars->dbtxn->ExecuteSQL( query );
};




//@ SEC 3
//@ CHA Field Relate Delete Field
//@ COD FieldRelateDeleteField
//@ TAB FieldDescriptor Write
//@ GEN Use FieldRelateFind to locate field relation records for a particular field

void FieldRelateDeleteField( XCBuffer* input, XCTransactionVars* vars ) {
	XCSQLGen* query = vars->query;
	XCCompare comp[3];
	XCField* fields[4];

	input->MoveUnlikeField( FLD_MSTR_FIELD_NBR, input, FLD_FIELD_NUMBER );
	fields[0] = input->GetField( FLD_APPL_NBR );
	fields[1] = input->GetField( FLD_MSTR_FIELD_NBR );
	fields[2] = input->GetField( FLD_FIELD_NUMBER );
	fields[3] = NULL;

	comp[1].preparen++;
	comp[1].logical = logic_or;
	comp[2].postparen++;

	query->MakeDELETE( input );
	query->AddWHERE( fields, comp );

	vars->dbtxn->ExecuteSQL( query, SQL_NO_RESULT );
};
